Jest ์ค์ ๋ฐ ์ปค์คํ Matcher ์์ฑ์ ํตํ ํจ๊ณผ์ ์ธ ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ ์๋ฒฝ ๊ฐ์ด๋. ์ ์ธ๊ณ ํ๋ก์ ํธ์ ์ฝ๋ ํ์ง๊ณผ ์ ๋ขฐ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ ๋ง์คํฐํ๊ธฐ: ๊ฒฌ๊ณ ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ Jest ์ค์ ๋ฐ ์ปค์คํ Matcher ํ์ฉ
๋น ๋ฅด๊ฒ ๋ณํํ๋ ์ค๋๋ ์ ์ํํธ์จ์ด ํ๊ฒฝ์์ ๊ฒฌ๊ณ ํ๊ณ ์ ๋ขฐํ ์ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ด๋ฌํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ์ด์์ ํจ๊ณผ์ ์ธ ํ ์คํธ์ ๋๋ค. ํ๋ก ํธ์๋์ ๋ฐฑ์๋ ๊ฐ๋ฐ ๋ชจ๋์์ ์ง๋ฐฐ์ ์ธ ์ธ์ด์ธ ์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ฐ๋ ฅํ๊ณ ๋ค์ฌ๋ค๋ฅํ ํ ์คํธ ํ๋ ์์ํฌ๋ฅผ ํ์๋ก ํฉ๋๋ค. ํ์ด์ค๋ถ์ด ๊ฐ๋ฐํ Jest๋ ์ ๋์ ์ธ ์ ํ์ง๋ก ๋ถ์ํ์ผ๋ฉฐ, ์ ๋ก ์ค์ (zero-configuration) ๋ฐฉ์, ๊ฐ๋ ฅํ ๋ชจํน ๊ธฐ๋ฅ, ๋ฐ์ด๋ ์ฑ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ด ์ข ํฉ ๊ฐ์ด๋์์๋ Jest ์ค์ ์ ๋ณต์กํ ๋ถ๋ถ์ ๊น์ด ํ๊ณ ๋ค๊ณ ์ปค์คํ Matcher(๋งค์ฒ) ์์ฑ์ ํ๊ตฌํ์ฌ, ์ฌ๋ฌ๋ถ์ ์์น๋ ํ๋ก์ ํธ ๊ท๋ชจ์ ๊ด๊ณ์์ด ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋์ ํ์ง๊ณผ ์ ๋ขฐ์ฑ์ ๋ณด์ฅํ๋ ๋ ํํ๋ ฅ ์๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ํ ์คํธ๋ฅผ ์์ฑํ ์ ์๋๋ก ์ง์ํฉ๋๋ค.
์ Jest์ธ๊ฐ? ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ์ ๊ธ๋ก๋ฒ ํ์ค
์ค์ ๊ณผ ์ปค์คํ Matcher์ ๋ํด ์์๋ณด๊ธฐ ์ ์, ์ Jest๊ฐ ์ ์ธ๊ณ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์๋ค์๊ฒ ํ์ ํ๋ ์์ํฌ๊ฐ ๋์๋์ง ์ดํดํด ๋ด ์๋ค:
- ์ ๋ก ์ค์ (Zero Configuration): Jest๋ ๋๋ผ์ธ ์ ๋๋ก ์ฌ์ด ์ค์ ์ ์๋ํ๋ฉฐ, ์ต์ํ์ ์ค์ ๋ง์ผ๋ก ํ ์คํธ ์์ฑ์ ์์ํ ์ ์๊ฒ ํด์ค๋๋ค. ์ด๋ ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ(TDD)์ด๋ ํ์ ์ฃผ๋ ๊ฐ๋ฐ(BDD) ๋ฐฉ์์ ์ฑํํ๋ ํ์๊ฒ ํนํ ์ ์ฉํฉ๋๋ค.
- ๋น ๋ฅด๊ณ ํจ์จ์ : Jest์ ๋ณ๋ ฌ ํ ์คํธ ์คํ๊ณผ ์บ์ฑ ๋ฉ์ปค๋์ฆ์ ๋น ๋ฅธ ํ ์คํธ ์ฃผ๊ธฐ์ ๊ธฐ์ฌํ์ฌ ๊ฐ๋ฐ ์ค ์ ์ํ ํผ๋๋ฐฑ์ ์ ๊ณตํฉ๋๋ค.
- ๋ด์ฅ๋ ๋ชจํน(Mocking): Jest๋ ๊ฐ๋ ฅํ ๋ชจํน ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฌ ์ฝ๋ ๋จ์๋ฅผ ๋ถ๋ฆฌํ๊ณ ํจ๊ณผ์ ์ธ ๋จ์ ํ ์คํธ๋ฅผ ์ํด ์์กด์ฑ์ ์๋ฎฌ๋ ์ด์ ํ ์ ์์ต๋๋ค.
- ์ค๋ ์ท ํ ์คํ (Snapshot Testing): Jest์ ์ค๋ ์ท ํ ์คํ ๊ธฐ๋ฅ์ UI ์ปดํฌ๋ํธ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๊ฒ์ฆํ๋ ๊ณผ์ ์ ๋จ์ํํ์ฌ ์์์น ๋ชปํ ๋ณ๊ฒฝ ์ฌํญ์ ์ฝ๊ฒ ๊ฐ์งํ ์ ์๊ฒ ํฉ๋๋ค.
- ํ๋ฅญํ ๋ฌธ์์ ์ปค๋ฎค๋ํฐ ์ง์: Jest๋ ํฌ๊ด์ ์ธ ๋ฌธ์์ ํ๋ฐํ ์ปค๋ฎค๋ํฐ๋ฅผ ๋ณด์ ํ๊ณ ์์ด ํ์ํ ๋ ๋ต์ ์ฐพ๊ณ ๋์์ ๋ฐ๊ธฐ ์ฝ์ต๋๋ค. ์ด๋ ๋ค์ํ ํ๊ฒฝ์์ ์์ ํ๋ ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ค์๊ฒ ๋งค์ฐ ์ค์ํฉ๋๋ค.
- ๋์ ์ฑํ๋ฅ : ์คํํธ์ ๋ถํฐ ๋๊ธฐ์ ์ ์ด๋ฅด๊ธฐ๊น์ง ์ ์ธ๊ณ ๊ธฐ์ ๋ค์ด ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ํ ์คํธ๋ฅผ ์ํด Jest์ ์์กดํ๊ณ ์์ต๋๋ค. ์ด์ฒ๋ผ ๊ด๋ฒ์ํ ์ฑํ์ ์ง์์ ์ธ ๊ฐ์ ๊ณผ ํ๋ถํ ๋ฆฌ์์ค๋ฅผ ๋ณด์ฅํฉ๋๋ค.
Jest ์ค์ ํ๊ธฐ: ํ ์คํธ ํ๊ฒฝ ๋ง์ถคํ
Jest๊ฐ ์ ๋ก ์ค์ ๊ฒฝํ์ ์ ๊ณตํ์ง๋ง, ํ๋ก์ ํธ์ ํน์ ์๊ตฌ์ ๋ง๊ฒ ์ฌ์ฉ์ ์ ์ํ๋ ๊ฒ์ด ์ข ์ข ํ์ํฉ๋๋ค. Jest๋ฅผ ์ค์ ํ๋ ์ฃผ์ ๋ฐฉ๋ฒ์ ํ๋ก์ ํธ์ ๋ฃจํธ์ ์๋ `jest.config.js` ํ์ผ(๋๋ TypeScript๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ `jest.config.ts`)์ ํตํ๋ ๊ฒ์ ๋๋ค. ๋ช ๊ฐ์ง ์ฃผ์ ์ค์ ์ต์ ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
`transform`: ์ฝ๋ ํธ๋์คํ์ผ๋ง
`transform` ์ต์ ์ Jest๊ฐ ํ ์คํธ๋ฅผ ์คํํ๊ธฐ ์ ์ ์์ค ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ๋ณํํด์ผ ํ๋์ง๋ฅผ ์ง์ ํฉ๋๋ค. ์ด๋ ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ ๊ธฐ๋ฅ, JSX, TypeScript ๋๋ ๊ธฐํ ๋นํ์ค ๊ตฌ๋ฌธ์ ์ฒ๋ฆฌํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ํธ๋์คํ์ผ๋ง์๋ Babel์ ์ฌ์ฉํฉ๋๋ค.
์์ (`jest.config.js`):
module.exports = {
transform: {
'^.+\.js$': 'babel-jest',
'^.+\.jsx$': 'babel-jest',
'^.+\.ts?$': 'ts-jest',
},
};
์ด ์ค์ ์ Jest์๊ฒ `.js` ๋ฐ `.jsx` ํ์ผ์ `babel-jest`๋ฅผ ์ฌ์ฉํ๊ณ , `.ts` ํ์ผ์ `ts-jest`๋ฅผ ์ฌ์ฉํ์ฌ ๋ณํํ๋๋ก ์ง์ํฉ๋๋ค. ํ์ํ ํจํค์ง(`npm install --save-dev babel-jest @babel/core @babel/preset-env ts-jest typescript`)๊ฐ ์ค์น๋์ด ์๋์ง ํ์ธํ์ธ์. ๊ธ๋ก๋ฒ ํ์ ๊ฒฝ์ฐ, ๋ชจ๋ ์ง์ญ์์ ์ฌ์ฉ๋๋ ์ ์ ํ ECMAScript ๋ฒ์ ์ ์ง์ํ๋๋ก Babel์ด ์ค์ ๋์๋์ง ํ์ธํด์ผ ํฉ๋๋ค.
`testEnvironment`: ์คํ ์ปจํ ์คํธ ์๋ฎฌ๋ ์ด์
`testEnvironment` ์ต์ ์ ํ ์คํธ๊ฐ ์คํ๋ ํ๊ฒฝ์ ์ง์ ํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ต์ ์๋ `node`(๋ฐฑ์๋ ์ฝ๋์ฉ)์ `jsdom`(DOM๊ณผ ์ํธ ์์ฉํ๋ ํ๋ก ํธ์๋ ์ฝ๋์ฉ)์ด ์์ต๋๋ค.
์์ (`jest.config.js`):
module.exports = {
testEnvironment: 'jsdom',
};
`jsdom`์ ์ฌ์ฉํ๋ฉด ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์ ์๋ฎฌ๋ ์ด์ ํ์ฌ React ์ปดํฌ๋ํธ๋ DOM์ ์์กดํ๋ ๋ค๋ฅธ ์ฝ๋๋ฅผ ํ ์คํธํ ์ ์์ต๋๋ค. Node.js ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ด๋ ๋ฐฑ์๋ ํ ์คํธ์ ๊ฒฝ์ฐ `node`๊ฐ ์ ํธ๋๋ ์ ํ์ ๋๋ค. ๊ตญ์ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์์ ํ ๋๋ `testEnvironment`๊ฐ ๋์ ๊ณ ๊ฐ๊ณผ ๊ด๋ จ๋ ๋ก์ผ์ผ ์ค์ ์ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ฎฌ๋ ์ด์ ํ๋์ง ํ์ธํด์ผ ํฉ๋๋ค.
`moduleNameMapper`: ๋ชจ๋ ์ํฌํธ ํด๊ฒฐ
`moduleNameMapper` ์ต์ ์ ์ฌ์ฉํ๋ฉด ๋ชจ๋ ์ด๋ฆ์ ๋ค๋ฅธ ๊ฒฝ๋ก์ ๋งคํํ ์ ์์ต๋๋ค. ์ด๋ ๋ชจ๋ ๋ชจํน, ์ ๋ ๊ฒฝ๋ก ์ํฌํธ ์ฒ๋ฆฌ, ๋๋ ๊ฒฝ๋ก ๋ณ์นญ ํด๊ฒฐ์ ์ ์ฉํฉ๋๋ค.
์์ (`jest.config.js`):
module.exports = {
moduleNameMapper: {
'^@components/(.*)$': '/src/components/$1',
},
};
์ด ์ค์ ์ `@components/`๋ก ์์ํ๋ ์ํฌํธ๋ฅผ `src/components` ๋๋ ํ ๋ฆฌ๋ก ๋งคํํฉ๋๋ค. ์ด๋ ์ํฌํธ๋ฅผ ๋จ์ํํ๊ณ ์ฝ๋ ๊ฐ๋ ์ฑ์ ํฅ์์ํต๋๋ค. ๊ธ๋ก๋ฒ ํ๋ก์ ํธ์ ๊ฒฝ์ฐ, ์ ๋ ๊ฒฝ๋ก ์ํฌํธ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์ํ ๋ฐฐํฌ ํ๊ฒฝ๊ณผ ํ ๊ตฌ์กฐ ์ ๋ฐ์ ๊ฑธ์ณ ์ ์ง๋ณด์์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
`testMatch`: ํ ์คํธ ํ์ผ ์ง์
`testMatch` ์ต์ ์ ํ ์คํธ ํ์ผ์ ์ฐพ๋ ๋ฐ ์ฌ์ฉ๋๋ ํจํด์ ์ ์ํฉ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก Jest๋ `.test.js`, `.spec.js`, `.test.jsx`, `.spec.jsx`, `.test.ts`, ๋๋ `.spec.ts`๋ก ๋๋๋ ํ์ผ์ ์ฐพ์ต๋๋ค. ํ๋ก์ ํธ์ ๋ช ๋ช ๊ท์น์ ๋ง๊ฒ ์ด๋ฅผ ์ฌ์ฉ์ ์ ์ํ ์ ์์ต๋๋ค.
์์ (`jest.config.js`):
module.exports = {
testMatch: ['/src/**/*.test.js'],
};
์ด ์ค์ ์ Jest์๊ฒ `src` ๋๋ ํ ๋ฆฌ์ ๊ทธ ํ์ ๋๋ ํ ๋ฆฌ ๋ด์์ `.test.js`๋ก ๋๋๋ ํ ์คํธ ํ์ผ์ ์ฐพ๋๋ก ์ง์ํฉ๋๋ค. ํ ์คํธ ํ์ผ์ ๋ํ ์ผ๊ด๋ ๋ช ๋ช ๊ท์น์ ํนํ ํฌ๊ณ ๋ถ์ฐ๋ ํ์์ ์ ์ง๋ณด์์ฑ์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
`coverageDirectory`: ์ปค๋ฒ๋ฆฌ์ง ์ถ๋ ฅ ์ง์
`coverageDirectory` ์ต์ ์ Jest๊ฐ ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ณด๊ณ ์๋ฅผ ์ถ๋ ฅํ ๋๋ ํ ๋ฆฌ๋ฅผ ์ง์ ํฉ๋๋ค. ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ถ์์ ํ ์คํธ๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ ์ค์ํ ๋ถ๋ถ์ ๋ค๋ฃจ๊ณ ์๋์ง ํ์ธํ๊ณ ์ถ๊ฐ ํ ์คํธ๊ฐ ํ์ํ ์ ์๋ ์์ญ์ ์๋ณํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
์์ (`jest.config.js`):
module.exports = {
coverageDirectory: 'coverage',
};
์ด ์ค์ ์ Jest๊ฐ ์ปค๋ฒ๋ฆฌ์ง ๋ณด๊ณ ์๋ฅผ `coverage`๋ผ๋ ์ด๋ฆ์ ๋๋ ํ ๋ฆฌ์ ์ถ๋ ฅํ๋๋ก ์ง์ํฉ๋๋ค. ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ณด๊ณ ์๋ฅผ ์ ๊ธฐ์ ์ผ๋ก ๊ฒํ ํ๋ฉด ์ฝ๋๋ฒ ์ด์ค์ ์ ๋ฐ์ ์ธ ํ์ง์ ๊ฐ์ ํ๊ณ ํ ์คํธ๊ฐ ์ค์ํ ๊ธฐ๋ฅ์ ์ ์ ํ ๋ค๋ฃจ๊ณ ์๋์ง ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ ํนํ ๊ตญ์ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ค์ํ ์ง์ญ์ ๊ฑธ์ณ ์ผ๊ด๋ ๊ธฐ๋ฅ๊ณผ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๋ณด์ฅํ๋ ๋ฐ ์ค์ํฉ๋๋ค.
`setupFilesAfterEnv`: ์ค์ ์ฝ๋ ์คํ
`setupFilesAfterEnv` ์ต์ ์ ํ ์คํธ ํ๊ฒฝ์ด ์ค์ ๋ ํ์ ์คํ๋์ด์ผ ํ ํ์ผ ๋ฐฐ์ด์ ์ง์ ํฉ๋๋ค. ์ด๋ ๋ชจ์(mock) ์ค์ , ์ ์ญ ๋ณ์ ๊ตฌ์ฑ ๋๋ ์ปค์คํ Matcher ์ถ๊ฐ์ ์ ์ฉํฉ๋๋ค. ์ด๊ฒ์ด ์ปค์คํ Matcher๋ฅผ ์ ์ํ ๋ ์ฌ์ฉํ๋ ์ง์ ์ ์ ๋๋ค.
์์ (`jest.config.js`):
module.exports = {
setupFilesAfterEnv: ['/src/setupTests.js'],
};
์ด๊ฒ์ Jest์๊ฒ ํ๊ฒฝ์ด ์ค์ ๋ ํ `src/setupTests.js`์ ์๋ ์ฝ๋๋ฅผ ์คํํ๋๋ก ์ง์ํฉ๋๋ค. ๋ค์ ์น์ ์์ ๋ค๋ฃฐ ์ปค์คํ Matcher๋ฅผ ๋ฑ๋กํ๋ ๊ณณ์ด ๋ฐ๋ก ์ฌ๊ธฐ์ ๋๋ค.
๊ธฐํ ์ ์ฉํ ์ค์ ์ต์ ๋ค
- `verbose`: ์ฝ์์ ์์ธํ ํ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ํ์ํ ์ง ์ฌ๋ถ๋ฅผ ์ง์ ํฉ๋๋ค.
- `collectCoverageFrom`: ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ณด๊ณ ์์ ํฌํจ๋ ํ์ผ์ ์ ์ํฉ๋๋ค.
- `moduleDirectories`: ๋ชจ๋์ ๊ฒ์ํ ์ถ๊ฐ ๋๋ ํ ๋ฆฌ๋ฅผ ์ง์ ํฉ๋๋ค.
- `clearMocks`: ํ ์คํธ ์คํ ์ฌ์ด์ ์๋์ผ๋ก ๋ชจ์(mock)๋ฅผ ์ง์๋๋ค.
- `resetMocks`: ๊ฐ ํ ์คํธ ์คํ ์ ์ ๋ชจ์(mock)๋ฅผ ์ฌ์ค์ ํฉ๋๋ค.
์ปค์คํ Matcher ๋ง๋ค๊ธฐ: Jest์ ๋จ์ธ(Assertion) ํ์ฅํ๊ธฐ
Jest๋ `toBe`, `toEqual`, `toBeTruthy`, `toBeFalsy`์ ๊ฐ์ ํ๋ถํ ๋ด์ฅ Matcher ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฌ๋ ํนํ ๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ๋๋ฉ์ธ ํน์ ๋ก์ง์ ๋ค๋ฃฐ ๋, ๋จ์ธ์ ๋ ๋ช ํํ๊ณ ๊ฐ๊ฒฐํ๊ฒ ํํํ๊ธฐ ์ํด ์ปค์คํ Matcher๋ฅผ ๋ง๋ค์ด์ผ ํ ๋๊ฐ ์์ต๋๋ค. ์ปค์คํ Matcher๋ ์ฝ๋ ๊ฐ๋ ์ฑ์ ํฅ์์ํค๊ณ ์ค๋ณต์ ์ค์ฌ ํ ์คํธ๋ฅผ ์ดํดํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
์ปค์คํ Matcher ์ ์ํ๊ธฐ
์ปค์คํ Matcher๋ `received` ๊ฐ(ํ ์คํธ ๋์ ๊ฐ)์ ๋ฐ๊ณ `pass`(๋จ์ธ ํต๊ณผ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ๋ถ๋ฆฌ์ธ)์ `message`(๋จ์ธ์ด ํต๊ณผํ๊ฑฐ๋ ์คํจํ ์ด์ ๋ฅผ ์ค๋ช ํ๋ ๋ฉ์์ง๋ฅผ ๋ฐํํ๋ ํจ์) ๋ ์์ฑ์ ํฌํจํ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ํจ์๋ก ์ ์๋ฉ๋๋ค. ์ซ์๊ฐ ํน์ ๋ฒ์ ๋ด์ ์๋์ง ํ์ธํ๋ ์ปค์คํ Matcher๋ฅผ ๋ง๋ค์ด ๋ด ์๋ค.
์์ (`src/setupTests.js`):
expect.extend({
toBeWithinRange(received, floor, ceiling) {
const pass = received >= floor && received <= ceiling;
if (pass) {
return {
message: () =>
`expected ${received} not to be within range ${floor} - ${ceiling}`,
pass: true,
};
} else {
return {
message: () =>
`expected ${received} to be within range ${floor} - ${ceiling}`,
pass: false,
};
}
},
});
์ด ์์์๋ `toBeWithinRange`๋ผ๋ ์ปค์คํ Matcher๋ฅผ ์ ์ํฉ๋๋ค. ์ด Matcher๋ `received` ๊ฐ(ํ ์คํธ ๋์ ์ซ์), `floor`(์ต์๊ฐ), `ceiling`(์ต๋๊ฐ)์ ์ธ ๊ฐ์ง ์ธ์๋ฅผ ๋ฐ์ต๋๋ค. Matcher๋ `received` ๊ฐ์ด ์ง์ ๋ ๋ฒ์ ๋ด์ ์๋์ง ํ์ธํ๊ณ `pass`์ `message` ์์ฑ์ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
์ปค์คํ Matcher ์ฌ์ฉํ๊ธฐ
์ปค์คํ Matcher๋ฅผ ์ ์ํ๋ค๋ฉด, ๋ค๋ฅธ ๋ด์ฅ Matcher์ ๋ง์ฐฌ๊ฐ์ง๋ก ํ ์คํธ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์์ (`src/myModule.test.js`):
import './setupTests'; // ์ปค์คํ
Matcher๊ฐ ๋ก๋๋์๋์ง ํ์ธ
describe('toBeWithinRange', () => {
it('passes when the number is within the range', () => {
expect(5).toBeWithinRange(1, 10);
});
it('fails when the number is outside the range', () => {
expect(0).not.toBeWithinRange(1, 10);
});
});
์ด ํ ์คํธ ์ค์ํธ๋ `toBeWithinRange` ์ปค์คํ Matcher๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. ์ฒซ ๋ฒ์งธ ํ ์คํธ ์ผ์ด์ค๋ ์ซ์ 5๊ฐ 1์์ 10 ์ฌ์ด์ ๋ฒ์์ ์๋ค๊ณ ๋จ์ธํ๊ณ , ๋ ๋ฒ์งธ ํ ์คํธ ์ผ์ด์ค๋ ์ซ์ 0์ด ๊ฐ์ ๋ฒ์์ ์์ง ์๋ค๊ณ ๋จ์ธํฉ๋๋ค.
๋ ๋ณต์กํ ์ปค์คํ Matcher ๋ง๋ค๊ธฐ
์ปค์คํ Matcher๋ ๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ๋๋ฉ์ธ ํน์ ๋ก์ง์ ํ ์คํธํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ฐฐ์ด์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์๊ณ ํน์ ์์๊ฐ ํฌํจ๋์ด ์๋์ง ํ์ธํ๋ ์ปค์คํ Matcher๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
์์ (`src/setupTests.js`):
expect.extend({
toContainIgnoreCase(received, expected) {
const pass = received.some(
(item) => item.toLowerCase() === expected.toLowerCase()
);
if (pass) {
return {
message: () =>
`expected ${received} not to contain ${expected} (case-insensitive)`,
pass: true,
};
} else {
return {
message: () =>
`expected ${received} to contain ${expected} (case-insensitive)`,
pass: false,
};
}
},
});
์ด Matcher๋ `received` ๋ฐฐ์ด์ ์ํํ๋ฉฐ ๊ฐ ์์๋ฅผ ์๋ฌธ์๋ก ๋ณํํ ํ, `expected` ๊ฐ(์ญ์ ์๋ฌธ์๋ก ๋ณํ๋จ)๊ณผ ์ผ์นํ๋์ง ํ์ธํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋ฐฐ์ด์ ๋ํด ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์๋ ๋จ์ธ์ ์ํํ ์ ์์ต๋๋ค.
๊ตญ์ ํ(i18n) ํ ์คํธ๋ฅผ ์ํ ์ปค์คํ Matcher
๊ตญ์ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ๋, ํ ์คํธ ๋ฒ์ญ์ด ์ฌ๋ฌ ๋ก์ผ์ผ์์ ์ ํํ๊ณ ์ผ๊ด์ ์ธ์ง ํ์ธํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ปค์คํ Matcher๋ ์ด ๋ชฉ์ ์ ๋งค์ฐ ์ ์ฉํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ง์ญํ๋ ๋ฌธ์์ด์ด ํน์ ํจํด๊ณผ ์ผ์นํ๋์ง ๋๋ ์ฃผ์ด์ง ์ธ์ด์ ๋ํ ํน์ ํค์๋๋ฅผ ํฌํจํ๋์ง ํ์ธํ๋ ์ปค์คํ Matcher๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
์์ (`src/setupTests.js` - ํค๋ฅผ ๋ฒ์ญํ๋ ํจ์๊ฐ ์๋ค๊ณ ๊ฐ์ ):
import { translate } from './i18n';
expect.extend({
toHaveTranslation(received, key, locale) {
const translatedString = translate(key, locale);
const pass = received.includes(translatedString);
if (pass) {
return {
message: () => `expected ${received} not to contain translation for key ${key} in locale ${locale}`,
pass: true,
};
} else {
return {
message: () => `expected ${received} to contain translation for key ${key} in locale ${locale}`,
pass: false,
};
}
},
});
์์ (`src/i18n.js` - ๊ธฐ๋ณธ์ ์ธ ๋ฒ์ญ ์์):
const translations = {
en: {
"welcome": "Welcome!"
},
fr: {
"welcome": "Bienvenue!"
}
}
export const translate = (key, locale) => {
return translations[locale][key];
};
์ด์ ํ ์คํธ์์ (`src/myComponent.test.js`):
import './setupTests';
it('should display translated greeting in french', () => {
const greeting = "Bienvenue!";
expect(greeting).toHaveTranslation("welcome", "fr");
});
์ด ์๋ `Bienvenue!`๊ฐ ํ๋์ค์ด๋ก ๋ "welcome"์ ๋ฒ์ญ๋ ๊ฐ์ธ์ง ํ ์คํธํฉ๋๋ค. ํน์ ๊ตญ์ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ ๊ทผ ๋ฐฉ์์ ๋ง๊ฒ `translate` ํจ์๋ฅผ ์กฐ์ ํด์ผ ํฉ๋๋ค. ์ ์ ํ i18n ํ ์คํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ค์ํ ๋ฌธํ์ ๋ฐฐ๊ฒฝ์ ๊ฐ์ง ์ฌ์ฉ์๋ค๊ณผ ๊ณต๊ฐ๋๋ฅผ ํ์ฑํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
์ปค์คํ Matcher์ ์ด์
- ๊ฐ๋ ์ฑ ํฅ์: ์ปค์คํ Matcher๋ ํนํ ๋ณต์กํ ๋จ์ธ์ ๋ค๋ฃฐ ๋ ํ ์คํธ๋ฅผ ๋ ํํ๋ ฅ ์๊ณ ์ดํดํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
- ์ค๋ณต ๊ฐ์: ์ปค์คํ Matcher๋ฅผ ์ฌ์ฉํ๋ฉด ๊ณตํต ๋จ์ธ ๋ก์ง์ ์ฌ์ฌ์ฉํ์ฌ ์ฝ๋ ์ค๋ณต์ ์ค์ด๊ณ ์ ์ง๋ณด์์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
- ๋๋ฉ์ธ ํน์ ๋จ์ธ: ์ปค์คํ Matcher๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ฉ์ธ์ ํนํ๋ ๋จ์ธ์ ๋ง๋ค์ด ํ ์คํธ๋ฅผ ๋ ๊ด๋ จ์ฑ ์๊ณ ์๋ฏธ ์๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
- ํฅ์๋ ํ์ : ์ปค์คํ Matcher๋ ํ ์คํธ ๊ดํ์ ์ผ๊ด์ฑ์ ์ฆ์ง์์ผ ํ์ด ํ ์คํธ ์ค์ํธ์์ ํ์ ํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
Jest ์ค์ ๋ฐ ์ปค์คํ Matcher๋ฅผ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
Jest ์ค์ ๊ณผ ์ปค์คํ Matcher์ ํจ๊ณผ๋ฅผ ๊ทน๋ํํ๋ ค๋ฉด ๋ค์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ ๋ คํ์ญ์์ค:
- ์ค์ ์ ๊ฐ๋จํ๊ฒ ์ ์ง: ๋ถํ์ํ ์ค์ ์ ํผํ์ธ์. ๊ฐ๋ฅํ ๋๋ง๋ค Jest์ ์ ๋ก ์ค์ ๊ธฐ๋ณธ๊ฐ์ ํ์ฉํ์ญ์์ค.
- ํ ์คํธ ํ์ผ ์ ๋ฆฌ: ํ ์คํธ ํ์ผ์ ๋ํ ์ผ๊ด๋ ๋ช ๋ช ๊ท์น์ ์ฑํํ๊ณ ํ๋ก์ ํธ ๊ตฌ์กฐ ๋ด์์ ๋ ผ๋ฆฌ์ ์ผ๋ก ์ ๋ฆฌํ์ญ์์ค.
- ๋ช ํํ๊ณ ๊ฐ๊ฒฐํ ์ปค์คํ Matcher ์์ฑ: ์ปค์คํ Matcher๊ฐ ์ดํดํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด์ง ํ์ธํ์ญ์์ค. ๋จ์ธ์ด ์คํจํ ์ด์ ๋ฅผ ๋ช ํํ๊ฒ ์ค๋ช ํ๋ ์ ์ฉํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ ๊ณตํ์ญ์์ค.
- ์ปค์คํ Matcher ํ ์คํธํ๊ธฐ: ์ปค์คํ Matcher๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๊ธฐ ์ํด ํ ์คํธ๋ฅผ ์์ฑํ์ญ์์ค.
- ์ปค์คํ Matcher ๋ฌธ์ํํ๊ธฐ: ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ด ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์ดํดํ ์ ์๋๋ก ์ปค์คํ Matcher์ ๋ํ ๋ช ํํ ๋ฌธ์๋ฅผ ์ ๊ณตํ์ญ์์ค.
- ๊ธ๋ก๋ฒ ์ฝ๋ฉ ํ์ค ์ค์: ์์น์ ๊ด๊ณ์์ด ๋ชจ๋ ํ์ ๊ฐ์ ์ฝ๋ ํ์ง๊ณผ ์ ์ง๋ณด์์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ํ๋ฆฝ๋ ์ฝ๋ฉ ํ์ค๊ณผ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ค์ํ์ญ์์ค.
- ํ ์คํธ์์ ํ์งํ ๊ณ ๋ ค: ๋ก์ผ์ผ๋ณ ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ i18n์ฉ ์ปค์คํ Matcher๋ฅผ ๋ง๋ค์ด ๋ค์ํ ์ธ์ด ์ค์ ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ ํ ๊ฒ์ฆํ์ญ์์ค.
๊ฒฐ๋ก : Jest๋ก ์ ๋ขฐํ ์ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถํ๊ธฐ
Jest๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ง๊ณผ ์ ๋ขฐ์ฑ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์๋ ๊ฐ๋ ฅํ๊ณ ๋ค์ฌ๋ค๋ฅํ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. Jest ์ค์ ๊ณผ ์ปค์คํ Matcher ์์ฑ์ ๋ง์คํฐํจ์ผ๋ก์จ ํ๋ก์ ํธ์ ํน์ ์๊ตฌ์ ๋ง๊ฒ ํ ์คํธ ํ๊ฒฝ์ ์กฐ์ ํ๊ณ , ๋ ํํ๋ ฅ ์๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ํ ์คํธ๋ฅผ ์์ฑํ๋ฉฐ, ์ฝ๋๊ฐ ๋ค์ํ ํ๊ฒฝ๊ณผ ์ฌ์ฉ์์ธต์์ ์์๋๋ก ์๋ํ๋์ง ํ์ธํ ์ ์์ต๋๋ค. ์์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋๊ท๋ชจ ์ํฐํ๋ผ์ด์ฆ ์์คํ ์ ๊ตฌ์ถํ๋ , Jest๋ ๊ธ๋ก๋ฒ ๊ณ ๊ฐ์ ์ํ ๊ฒฌ๊ณ ํ๊ณ ์ ๋ขฐํ ์ ์๋ ์ํํธ์จ์ด๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ํ์ํ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. Jest๋ฅผ ๋ฐ์๋ค์ด๊ณ ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ ๊ดํ์ ์๋ก์ด ์ฐจ์์ผ๋ก ๋์ด์ฌ๋ ค, ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ๋ง์กฑ์ํค๋ ๋ฐ ํ์ํ ํ์ค์ ์ถฉ์กฑํ๋ค๋ ์์ ๊ฐ์ ๊ฐ์ง์ญ์์ค.